/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version 1.1 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain
 * a copy of the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 *
 * The Original Code is [Open Source Virtual Machine.]
 *
 * The Initial Developer of the Original Code is Adobe System Incorporated.  Portions created
 * by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
 * Reserved.
 *
 * Contributor(s): Adobe AS3 Team
 *                 Andreas Gal <gal@mozilla.com>
 *
 * Alternatively, the contents of this file may be used under the terms of either the GNU
 * General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
 * License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
 * LGPL are applicable instead of those above. If you wish to allow use of your version of this
 * file only under the terms of either the GPL or the LGPL, and not to allow others to use your
 * version of this file under the terms of the MPL, indicate your decision by deleting provisions
 * above and replace them with the notice and other provisions required by the GPL or the
 * LGPL. If you do not delete the provisions above, a recipient may use your version of this file
 * under the terms of any one of the MPL, the GPL or the LGPL.
 *
 ***** END LICENSE BLOCK ***** */


/*
 *  nanojit-support.h
 *  joosVM
 *
 *  Created by Smári Waage on 11.11.2009.
 *
 *	Support classes for nanojit.
 */
#ifndef nanojit_support___ 
#define nanojit_support___ 


#include <stdarg.h>
#include "nanojit/nanojit.h"
#include "constants.h"

using namespace nanojit;
using namespace std;


class TraceRecorder;

class VMAllocator : public nanojit::Allocator
{
	
public:
    VMAllocator() : mOutOfMemory(false), mSize(0)
    {}
	
    size_t size() {
        return mSize;
    }
	
    bool outOfMemory() {
        return mOutOfMemory;
    }
	
    struct Mark
    {
        VMAllocator& vma;
        bool committed;
        nanojit::Allocator::Chunk* saved_chunk;
        char* saved_top;
        char* saved_limit;
        size_t saved_size;
		
        Mark(VMAllocator& vma) :
		vma(vma),
		committed(false),
		saved_chunk(vma.current_chunk),
		saved_top(vma.current_top),
		saved_limit(vma.current_limit),
		saved_size(vma.mSize)
        {}
		
        ~Mark()
        {
            if (!committed)
                vma.rewind(*this);
        }
		
        void commit() { committed = true; }
    };
	
    void rewind(const Mark& m) {
        while (current_chunk != m.saved_chunk) {
            Chunk *prev = current_chunk->prev;
            freeChunk(current_chunk);
            current_chunk = prev;
        }
        current_top = m.saved_top;
        current_limit = m.saved_limit;
        mSize = m.saved_size;
        memset(current_top, 0, current_limit - current_top);
    }
	
    bool mOutOfMemory;
    size_t mSize;
	
    /*
     * FIXME: Area the LIR spills into if we encounter an OOM mid-way
     * through compilation; we must check mOutOfMemory before we run out
     * of mReserve, otherwise we're in undefined territory. This area
     * used to be one page, now 16 to be "safer". This is a temporary
     * and quite unsatisfactory approach to handling OOM in Nanojit.
     */
    uintptr_t mReserve[0x10000];
};



/*
 * Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not
 * JS_THREADSAFE) has an associated trace monitor that keeps track of loop
 * frequencies for all JavaScript code loaded into that runtime.
 */
struct JSTraceMonitor {
    /*
     * The context currently executing JIT-compiled code on this thread, or
     * NULL if none. Among other things, this can in certain cases prevent
     * last-ditch GC and suppress calls to JS_ReportOutOfMemory.
     *
     * !tracecx && !recorder: not on trace
     * !tracecx && recorder: recording
     * tracecx && !recorder: executing a trace
     * tracecx && recorder: executing inner loop, recording outer loop
     */
    JSContext               *tracecx;
	
    /*
     * There are 3 allocators here. This might seem like overkill, but they
     * have different lifecycles, and by keeping them separate we keep the
     * amount of retained memory down significantly.
     *
     * The dataAlloc has the lifecycle of the monitor. It's flushed only
     * when the monitor is flushed.
     *
     * The traceAlloc has the same flush lifecycle as the dataAlloc, but
     * it is also *marked* when a recording starts and rewinds to the mark
     * point if recording aborts. So you can put things in it that are only
     * reachable on a successful record/compile cycle.
     *
     * The tempAlloc is flushed after each recording, successful or not.
     */
	
    VMAllocator*            dataAlloc;   /* A chunk allocator for fragments. */
    VMAllocator*            traceAlloc;  /* An allocator for trace metadata. */
    VMAllocator*            tempAlloc;   /* A temporary chunk allocator.  */
    nanojit::CodeAlloc*     codeAlloc;   /* An allocator for native code. */
    nanojit::Assembler*     assembler;
    nanojit::LirBuffer*     lirbuf;
    nanojit::LirBuffer*     reLirBuf;
	// FrameInfoCache*         frameCache;
#ifdef DEBUG
    nanojit::LabelMap*      labels;
#endif
	
    TraceRecorder*          recorder;
	// jsval                   *reservedDoublePool;
    //jsval                   *reservedDoublePoolPtr;
	
	// struct GlobalState      globalStates[MONITOR_N_GLOBAL_STATES];
	// struct VMFragment*      vmfragments[FRAGMENT_TABLE_SIZE];
	// JSDHashTable            recordAttempts;
	
    /*
     * Maximum size of the code cache before we start flushing. 1/16 of this
     * size is used as threshold for the regular expression code cache.
     */
    uint32_t                  maxCodeCacheBytes;
	
    /*
     * If nonzero, do not flush the JIT cache after a deep bail. That would
     * free JITted code pages that we will later return to. Instead, set the
     * needFlush flag so that it can be flushed later.
     */
    //JSBool                  needFlush;
	
    /*
     * reservedObjects is a linked list (via fslots[0]) of preallocated JSObjects.
     * The JIT uses this to ensure that leaving a trace tree can't fail.
     */
    //JSBool                  useReservedObjects;
	// JSObject                *reservedObjects;
	
    /*
     * Fragment map for the regular expression compiler.
     */
	//  REHashMap*              reFragments;
	
    /*
     * A temporary allocator for RE recording.
     */
    VMAllocator*            reTempAlloc;
	
#ifdef DEBUG
    /* Fields needed for fragment/guard profiling. */
    nanojit::Seq<nanojit::Fragment*>* branches;
    uint32                  lastFragID;
    /*
     * profAlloc has a lifetime which spans exactly from js_InitJIT to
     * js_FinishJIT.
     */
    VMAllocator*            profAlloc;
    FragStatsMap*           profTab;
#endif
	
    /* Flush the JIT cache. */
    void flush();
	
    /* Mark all objects baked into native code in the code cache. */
	// void mark(JSTracer *trc);
};

class TraceJIT{	
public:
	static void InitJIT(JSTraceMonitor *tm);
};

#endif
